package com.shaoyu.spring.study.util;

import com.shaoyu.spring.study.annotation.Column;
import com.shaoyu.spring.study.dto.ColumnBaseInfo;
import com.shaoyu.spring.study.dto.ExcelRequest;
import com.shaoyu.spring.study.dto.ExcelSheetRequest;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;


/**
 * @author : Swicky
 * @date : 2021/7/9 - 11:18 上午
 */
public class ExcelUtil {

    public static Workbook createWorkbook(ExcelRequest request) {
        return createWorkbook(request,"default");
    }

    /**
     * @param request
     * @param group
     * @return
     */
    public static Workbook createWorkbook(ExcelRequest request, String group) {
        List<ExcelSheetRequest> excelSheetRequests = request.getExcelSheetRequests();
        Workbook workbook = new XSSFWorkbook();
        sheet: for (ExcelSheetRequest excelSheetRequest : excelSheetRequests) {
            try{
                createSheet(excelSheetRequest,workbook,group);
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
        return workbook;
    }

    private static void createSheet(ExcelSheetRequest excelSheetRequest, Workbook workbook,String group)throws NoSuchMethodException  {
        String sheetName = excelSheetRequest.getSheetName();
        int rowIndex = 0;
        List excelData = excelSheetRequest.getExcelData();
        Sheet sheet = workbook.createSheet(sheetName);
        //Sheet 数据为空跳过
        if(CollectionUtils.isEmpty(excelData)){
            return;
        }
        Class t = excelData.get(0).getClass();
        Field[] fields = t.getDeclaredFields();
        //key=field.name  value = getMethod
        Map<String,Method> fieldMethods = new HashMap<>();
        List<ColumnBaseInfo> columns = new ArrayList<>();
        //获取公用数据 标题和方法等
        title:for (Field field : fields) {
            String name = field.getName();
            if(name.equals("serialVersionUID")) {
                continue title;
            }
            Method method ;
            if(field.getType().getSimpleName().toLowerCase().equals("boolean")){
                method = t.getDeclaredMethod("is"+name.substring(0,1).toUpperCase()+name.substring(1));
            }else {
                method = t.getDeclaredMethod("get"+name.substring(0,1).toUpperCase()+name.substring(1));
            }
            fieldMethods.put(name, method);
            Column column = field.getAnnotation(Column.class);
            if(column==null){
                //该属性没有设置注解就忽略
                continue title;
            }
            String[] groups = column.groups();
            List<String> groupList = Arrays.asList(groups);
            if(!groupList.contains(group)){
                //该属性的可执行的分组 不包含本次的分组 忽略该属性
                continue title;
            }
            columns.add(ColumnBaseInfo.of(column,field));
        }
        //设置线条
        CellStyle cellStyle = workbook.createCellStyle();
        cellStyle.setBorderBottom(BorderStyle.THIN);
        cellStyle.setBorderLeft(BorderStyle.THIN);
        cellStyle.setBorderRight(BorderStyle.THIN);
        cellStyle.setBorderTop(BorderStyle.THIN);
        //设置标题
        if(CollectionUtils.isNotEmpty(columns)){
            Row title = sheet.createRow(rowIndex++);
            //排序
            columns.sort(Comparator.comparingInt(o -> o.getColumn().sort()));
            AtomicInteger cellIndex = new AtomicInteger(0);
            columns.stream().forEach(column -> {
                //Cell下标
                int cellIndexIntValue = cellIndex.getAndIncrement();
                //设置单元格宽度
                int width = column.getColumn().width();
                if(width > 0){
                    sheet.setColumnWidth(cellIndexIntValue,width<<9);
                }
                Cell cell = title.createCell(cellIndexIntValue);
                cell.setCellStyle(cellStyle);
                String titleValue = column.getColumn().title();
                cell.setCellValue(("".equals(titleValue)||titleValue==null)?column.getField().getName():titleValue);
            });
            for (Object data: excelData) {
                Row dataRow = sheet.createRow(rowIndex++);
                cellIndex.set(0);
                columns.stream().forEach(column -> {
                    Method getMethod = fieldMethods.get(column.getField().getName());
                    getMethod.setAccessible(true);
                    try {
                        Object cellValue = getMethod.invoke(data);
                        Cell cell = dataRow.createCell(cellIndex.getAndIncrement());
                        cell.setCellStyle(cellStyle);
                        setCellValue(cell,cellValue);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                });
            }
            return;
        }
        Set<String> fieldNames = fieldMethods.keySet();
        Row title = sheet.createRow(rowIndex++);
        AtomicInteger cellIndex = new AtomicInteger(0);
        for (String fieldName : fieldNames) {
            Cell cell = title.createCell(cellIndex.getAndIncrement());
            cell.setCellStyle(cellStyle);
            cell.setCellValue(fieldName);
        }
        for (Object data: excelData) {
            Row dataRow = sheet.createRow(rowIndex++);
            cellIndex.set(0);
            fieldNames.stream().forEach(fieldName -> {
                Method getMethod = fieldMethods.get(fieldName);
                getMethod.setAccessible(true);
                try {
                    Object cellValue = getMethod.invoke(data);
                    Cell cell = dataRow.createCell(cellIndex.getAndIncrement());
                    cell.setCellStyle(cellStyle);
                    setCellValue(cell,cellValue);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            });
        }

    }

    private static void setCellValue(Cell cell, Object cellValue) {
        if(cellValue == null){
            cell.setCellValue("");
            return;
        }
        if(cellValue instanceof Integer){
            cell.setCellValue((int)cellValue);
        }else if(cellValue instanceof Double){
            cell.setCellValue((double)cellValue);
        }else if (cellValue instanceof Date) {
            Date dateValue = (Date) cellValue;
            cell.setCellValue(dateValue.toLocaleString());
        }else if (cellValue instanceof LocalDateTime) {
            LocalDateTime localDateTimeValue = (LocalDateTime) cellValue;
            cell.setCellValue(localDateTimeValue.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
        }else if (cellValue instanceof LocalDate) {
            LocalDate localDateValue = (LocalDate) cellValue;
            cell.setCellValue(localDateValue.format(DateTimeFormatter.ISO_LOCAL_DATE));
        }else if (cellValue instanceof Calendar) {
            Calendar calendarValue = (Calendar) cellValue;
            cell.setCellValue(calendarValue.toString());
        }else if (cellValue instanceof RichTextString) {
            cell.setCellValue((RichTextString)cellValue);
        }else {
            //除了上述以外 其他的都使用 String
            cell.setCellValue(cellValue.toString());
        }
    }

    public static void main(String[] args) throws IOException {
        List<Demo> data = new ArrayList<>();
        data.add(new Demo(1,1.2,"asd",new Date()));
        data.add(new Demo(2,3.2,"dkkdek",new Date()));
        data.add(new Demo(3,4.2,"csijoqw",new Date()));
        data.add(new Demo(4,5.2,"sadfiowjdiqjwodjqoiwdjoqwijdoiwqjdw",new Date()));
        Workbook workbook = ExcelUtil.createWorkbook(ExcelRequest.ofSingle("demo", data), "default");
        File file = new File("/Users/swicky/Desktop/test.xlsx");
        FileOutputStream outputStream = new FileOutputStream(file);
        workbook.write(outputStream);
        outputStream.close();
        workbook.close();
    }

    static class Demo{
        @Column(title = "标题1",sort = 99,width = 5)
        private int a;

        @Column(title = "标题2",sort = 1,width = 5)
        private double b;

        @Column(title = "标题3",sort = 2,width = 10)
        private String c;

        @Column(title = "标题4",sort = 3,width = 16)
        private Date d;

        public Demo(int a, double b, String c, Date d) {
            this.a = a;
            this.b = b;
            this.c = c;
            this.d = d;
        }

        public int getA() {
            return a;
        }

        public void setA(int a) {
            this.a = a;
        }

        public double getB() {
            return b;
        }

        public void setB(double b) {
            this.b = b;
        }

        public String getC() {
            return c;
        }

        public void setC(String c) {
            this.c = c;
        }

        public Date getD() {
            return d;
        }

        public void setD(Date d) {
            this.d = d;
        }
    }
}
